package org.manager.menu;

import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.manager.authorize.Function;
import org.manager.authorize.SystemRole;
import org.manager.generic.Repository.GenericHibernateRepository;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.stereotype.Repository;

@SuppressWarnings("unchecked")
@Repository("menuRepository")
public class MenuRepositoryImpl extends GenericHibernateRepository<Menu> implements MenuRepository {

	public String getMenuJsonData() {
		return (String)getHibernateTemplate().execute(new HibernateCallback(){
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				StringBuffer json = new StringBuffer("[");
				//Criteria criteria = CriteriaUtil.createCacheCriteria(session, Menu.class);
				//Iterator<Menu> mlist= criteria.add(Restrictions.isNull("parentId"));
				Iterator<Menu> menuIterator = session.createQuery("from Menu where parentId is null").iterate();
				
				boolean flag = false;
				while(menuIterator.hasNext()){
					Menu m = menuIterator.next();
					if(flag) json.append(",");
					json.append(recursionMenu2Json(m));
					flag = true;
				}
				
				json.append("]");
				return json.toString();
			}
		});
	}
	
	//REFACTOR:大量使用了拼接，无法复用，内性不强。
	private String recursionMenu2Json(Menu m){
		StringBuffer json = new StringBuffer("{");
		json.append("name:'"+null2String(m.getName()));
		json.append("',id:'"+null2String(m.getId()));
		json.append("',code:'"+null2String(m.getCode()));
		json.append("',link:'"+null2String(m.getLink()));
		json.append("',parentCode:'"+null2String(m.getParentCode()));
		json.append("',parentId:'"+null2String(m.getParentId()));
		json.append("',status:'"+null2String(m.getStatus()));
		json.append("',canBeDelete:'"+null2String(m.getCanBeDelete()));
		json.append("',canBeDeleteZw:'"+ (StringUtils.equals(m.getCanBeDelete(), "1")?"否":"是"));
		json.append("',checked:false");
		
		if(m.getChildMenus() != null && m.getChildMenus().size() > 0){
			json.append(",expanded:true,children:[");
			boolean flag = false;
			for(Menu subMenu : m.getChildMenus()){
				if(flag){json.append(",");}
				json.append(recursionMenu2Json(subMenu));
				flag = true;
			}
			json.append("]");
		}else{
			json.append(",leaf:true");
		}
		json.append("}");
		return json.toString();
	}
	
	
	public void addMenu(final Menu menu) {
		//得到本级别最小code.
		List<String> codeList = getHibernateTemplate().executeFind(new HibernateCallback(){
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				if(StringUtils.isBlank(menu.getParentCode())){
					return session.createQuery("select code from Menu where parentCode is null").list();
				}else{
					return session.createQuery("select code from Menu where parentCode = :code")
						.setParameter("code", menu.getParentCode()).list();
				}
			}
		});
		
		if(menu.getParentCode() == null){
			menu.setCode(Integer.toString(getMaxCodeByLevel(codeList)+1));
			save(menu);
		}else{
			menu.setCode(menu.getParentCode()+"."+(getMaxCodeByLevel(codeList)+1));
			addMenuToParent(menu);
		}
	}
	
	private void addMenuToParent(final Menu menu){
		if(menu != null && StringUtils.isNotBlank(menu.getParentId())){
			getHibernateTemplate().execute(new HibernateCallback(){
				@Override
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					Menu parent = (Menu)session.load(Menu.class, menu.getParentId());
					parent.addChildMenu(menu);
					session.save(menu);
					return null;
				}
			});
		}
	}
	
	
	public int deleteMenu(final String[] ids) {
		return (Integer)getHibernateTemplate().execute(new HibernateCallback(){
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				for(String id : ids){
					Menu menu = (Menu)session.get(Menu.class, id);
					if(menu != null && StringUtils.isNotBlank(menu.getParentId())){
						Menu parent = (Menu)session.get(Menu.class, menu.getParentId());
						if(parent != null){
							parent.getChildMenus().remove(menu);
						}
					}else if(menu != null){
						session.delete(menu);
					}
				}
				return ids.length;
			}
		});
	}
	
	
	@Override
	public String getMenuAuthorityData(final String[] roleIdArray) {
		return (String)getHibernateTemplate().execute(new HibernateCallback(){
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				//如果是对单个角色进行授权，则查出该角色备用.
				SystemRole role = null;
				if(roleIdArray.length == 1 && StringUtils.isNotBlank(roleIdArray[0])){
					role = (SystemRole)session.get(SystemRole.class,roleIdArray[0]);
				}
				
				StringBuffer json = new StringBuffer("[");
				//查询出所有跟节点的菜单.
				Iterator<Menu> menuIterator = session.createQuery("from Menu where parentId is null").iterate();
				boolean flag = false;
				while(menuIterator.hasNext()){
					Menu menu = menuIterator.next();
					if(flag) json.append(",");
					//递归拼接json.
					json.append(recursionAuthorityMenu2Json(role,menu));
					flag = true;
				}
				
				json.append("]");
				return json.toString();
			}
		});
	}
	
	/**
	 * 动态拼接menu的json，如果该角色已经具备该menu的操作权限，应当checked=true.
	 * 如果role为null，则证明是同时对多个角色进行授权，不在查询角色已有的功能.
	 * REFACTOR:拼接很弱智.看能不能重构.
	 * @param role 角色.
	 * @param menu 菜单.
	 * @return
	 */
	private String recursionAuthorityMenu2Json(SystemRole role, Menu menu){
		StringBuffer json = new StringBuffer("{");
		json.append("name:'"+null2String(menu.getName()));
		json.append("',id:'"+null2String(menu.getId()));
		json.append("',code:'"+null2String(menu.getCode()));
		//权限数据.
		Function fun;
		if(role != null){
			fun = role.containsFunction(menu.getFunctionSet());
		}else{
			fun = new Function();
		}
		 
		json.append("',add:'<input type=checkbox "+fun.isAddChecked()+" id="+null2String(menu.getId())+"_add_check name="+null2String(menu.getId())+"_add_check onclick=clickAuthority(\""+null2String(menu.getId())+"\") >");
		json.append("',del:'<input type=checkbox "+fun.isDelChecked()+" id="+null2String(menu.getId())+"_del_check name="+null2String(menu.getId())+"_del_check onclick=clickAuthority(\""+null2String(menu.getId())+"\") >");
		json.append("',modify:'<input type=checkbox "+fun.isModifyChecked()+" id="+null2String(menu.getId())+"_modify_check name="+null2String(menu.getId())+"_modify_check onclick=clickAuthority(\""+null2String(menu.getId())+"\") >");
		json.append("',import:'<input type=checkbox "+fun.isImpChecked()+" id="+null2String(menu.getId())+"_import_check name="+null2String(menu.getId())+"_import_check onclick=clickAuthority(\""+null2String(menu.getId())+"\") >");
		json.append("',export:'<input type=checkbox "+fun.isExpChecked()+" id="+null2String(menu.getId())+"_export_check name="+null2String(menu.getId())+"_export_check onclick=clickAuthority(\""+null2String(menu.getId())+"\") >");
		json.append("',checked:"+fun.hasFunctonChecked());
		
		if(menu.getChildMenus() != null && menu.getChildMenus().size() > 0){
			json.append(",expanded:true,children:[");
			boolean flag = false;
			for(Menu subMenu : menu.getChildMenus()){
				if(flag){json.append(",");}
				json.append(recursionAuthorityMenu2Json(role,subMenu));
				flag = true;
			}
			json.append("]");
		}else{
			json.append(",leaf:true");
		}
		json.append("}");
		return json.toString();
	}
	
	
	/**
	 * 输入一个code的list结构如:[1.1][1.2][1.3].找到本级最大编号:3.
	 * @param codeList
	 * @return
	 */
	private int getMaxCodeByLevel(List<String> codeList){
		int maxCode = 0;
		for(String code: codeList){
			//判断每一个code是否合法，并记录最大的一个.
			if(code.lastIndexOf(".") == -1){
				if(NumberUtils.isNumber(code)){
					if(NumberUtils.toInt(code) > maxCode){
						maxCode = NumberUtils.toInt(code);
					}
				}
			}else{
				code = code.substring(code.lastIndexOf(".")+1, code.length());
				if(NumberUtils.isNumber(code)){
					if(NumberUtils.toInt(code) > maxCode){
						maxCode = NumberUtils.toInt(code);
					}//
				}//
			}//end of else.
		}
		return maxCode;
	}
	
	private String null2String(String property){
		if(property == null){
			return "";
		}else{
			return property;
		}
	}
	
}
